package edu.llg.oojcodesandbox;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import edu.llg.oojcodesandbox.model.ExecuteCodeRequest;
import edu.llg.oojcodesandbox.model.ExecuteCodeResult;
import edu.llg.oojcodesandbox.model.ExecuteMessage;
import edu.llg.oojcodesandbox.model.JudgeInfo;
import edu.llg.oojcodesandbox.model.enums.JudgeInfoMessageEnum;
import edu.llg.oojcodesandbox.utils.ProcessExecuteUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * @author 隆利果
 * @version 1.0
 * @date 2024/2/7 19:43
 */
@Slf4j
@Component
@Deprecated
public class JavaNativeCodeSandBoxImpl implements CodeSandBox {

    private static final String GLOBAL_CODE_PATH = "tmpCode";

    private static final String GLOBAL_CODE_NAME = "Main.java";

    private static final Long TIME_OUT = 5000L;


    public static void main(String[] args) {
        JavaNativeCodeSandBoxImpl javaCodeSandBox = new JavaNativeCodeSandBoxImpl();
        ExecuteCodeRequest executeCodeRequest = new ExecuteCodeRequest();

        executeCodeRequest.setInputList(Arrays.asList("1 2"));
        executeCodeRequest.setCode("public class Main {\n" +
                "    public static void main(String[] args) {\n" +
                "            int a = Integer.parseInt(args[0]);\n" +
                "            int b = Integer.parseInt(args[1]);\n" +
                "            System.out.println((a+b));\n" +
                "    }\n" +
                "}");
        executeCodeRequest.setLanguage("java");

        ExecuteCodeResult executeCodeResult = javaCodeSandBox.executeCode(executeCodeRequest);
        System.out.println(executeCodeResult);
    }

    @Override
    public ExecuteCodeResult executeCode(ExecuteCodeRequest executeCodeRequest) {
        /**
         * 1. 接受代码保存成文件
         */
        List<String> inputList = executeCodeRequest.getInputList();
        String code = executeCodeRequest.getCode();
        String language = executeCodeRequest.getLanguage();

        String rootPath = System.getProperty("user.dir");
        String userCodeRootPath = rootPath + File.separator + GLOBAL_CODE_PATH;

        if (!FileUtil.exist(userCodeRootPath)) {
            FileUtil.mkdir(userCodeRootPath);
        }

        String userCodeParentPath = userCodeRootPath + File.separator + UUID.randomUUID();
        String userCodePath = userCodeParentPath + File.separator + GLOBAL_CODE_NAME;
        File userCodeFile = FileUtil.writeString(code, userCodePath, StandardCharsets.UTF_8);


        /**
         * 编译代码 得到结果
         */
        String compileCmd = String.format("javac -encoding utf-8 %s", userCodeFile.getAbsolutePath());
        try {
            /**
             * 开启一个新的子进程准备运行命令
             */
            Process exec = Runtime.getRuntime().exec(compileCmd);
            ExecuteMessage executeMessage = ProcessExecuteUtil.runProcess(exec, "编译");
            Integer exitValue = executeMessage.getExitValue();
            if (exitValue != 0) {
                return packageErrorMessage(JudgeInfoMessageEnum.COMPILE_ERROR.getValue());
            }
        } catch (IOException e) {
            return packageErrorMessage(JudgeInfoMessageEnum.COMPILE_ERROR.getValue());
        }

        /**
         * 运行代码
         */
        List<ExecuteMessage> executeMessageList = new ArrayList<>();
        for (String inputArgs : inputList) {
            String runCmd = String.format("java -Xmx256m -Dfile.encoding=UTF-8 -cp %s Main %s", userCodeParentPath, inputArgs);
            try {
                Process runProcess = Runtime.getRuntime().exec(runCmd);
                new Thread(() -> {
                    try {
                        Thread.sleep(TIME_OUT);
                        System.out.println("超时了");
                        runProcess.destroy();
                    } catch (InterruptedException e) {
                    }
                }).start();
                ExecuteMessage executeMessage = ProcessExecuteUtil.runProcess(runProcess, "运行");
                if(executeMessage.getJudgeInfo().getTime() > TIME_OUT){
                    return packageErrorMessage(JudgeInfoMessageEnum.TIME_LIMIT_EXCEEDED.getValue());
                }
                System.out.println("运行结果==" + executeMessage);
                executeMessageList.add(executeMessage);
            } catch (IOException e) {
                return packageErrorMessage(JudgeInfoMessageEnum.RUNTIME_ERROR.getValue());
            }
        }

        /**
         * 获取整理输出结果
         */
        ExecuteCodeResult executeCodeResult = new ExecuteCodeResult();

        List<String> outputList = new ArrayList<>();

        long maxTime = 0;
        for (ExecuteMessage executeMessage : executeMessageList) {
            Long time = executeMessage.getJudgeInfo().getTime();
            maxTime = Math.max(maxTime, time);
            if (executeMessage.getExitValue() != 0) {
                //执行失败
                executeCodeResult.setStatus(3);
                executeCodeResult.setMessage(executeMessage.getJudgeInfo().getMessage());
                break;
            } else {
                outputList.add(executeMessage.getJudgeInfo().getMessage());
            }
        }
        if (outputList.size() == executeMessageList.size()){
            executeCodeResult.setStatus(2);
        }

        JudgeInfo judgeInfo = new JudgeInfo();
        judgeInfo.setTime(maxTime);

        executeCodeResult.setOutputList(outputList);
        executeCodeResult.setJudgeInfo(judgeInfo);

        /**
         * 文件清理
         */
        String absolutePath = userCodeFile.getParentFile().getAbsolutePath();
        if(FileUtil.exist(absolutePath)){
            FileUtil.del(absolutePath);
            System.out.println("删除文件成功");
        }else{
            log.error("deleteFile error, userCodeFilePath = {}", userCodeFile.getAbsolutePath());
        }

        return executeCodeResult;
    }

    private ExecuteCodeResult packageErrorMessage(String message){
        ExecuteCodeResult executeCodeResult = new ExecuteCodeResult();
        executeCodeResult.setMessage(message);
        executeCodeResult.setStatus(3);
        executeCodeResult.setOutputList(new ArrayList<>());
        executeCodeResult.setJudgeInfo(new JudgeInfo());
        return executeCodeResult;
    }

}
